<?php
/**
 * Lib\Pidguin\Client - class client
 *
 * @author Eni
 * @version 1.2.1
 */
class Pidguin_Client
{
	/**
	 * @var object UserRow
	 */
	protected $_client = null;
	
	/**
	 * @var object Zend_Acl
	 */
	protected $_acl = null;
	
	/**
	 * @var object User
	 */
	protected $_userModel = null;
	
	/**
	 * @var object Client
	 */
	protected $_clientModel = null;
	
	/**
	 * @var int
	 */
	protected $_userId = 0;
	
	/**
	 * Object user agent
	 *
	 * @var object Zend_Http_UserAgent
	 */
	protected $_userAgent = null;
	
	/**
	 * @var string
	 */
	protected $_deviceType = '';
	
	/**
	 * Instance of class
	 *
	 * @var Pidguin_Client
	 */
	private static $_instance = null;
	
	/**
	 * Get instance of class
	 *
	 * @return Pidguin_Client
	 */
	public static function getInstance()
	{
		if (self::$_instance === null) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}
	
	public function __construct()
	{
		
	}
	
	public function getClient()
	{
		return $this->_client;
	}
	
	/**
	 * Get client id from the data
	 *
	 * @return string
	 */
	public function getClientIdFromData()
	{
		$browser = $this->getClientBrowserName();
		$userAgentFull = $_SERVER['HTTP_USER_AGENT'];
		
		$this->_deviceType = $this->getDeviceType();
		
		$clientRow = $this->getClientModel()->findBySid($sid);
		var_dump($clientRow); die();
		$dataSession = '';
		if ($clientRow) {
			$dataSession = $clientRow->created_at;
		}
		
		return hash('sha256', $browser . $this->_deviceType . $dataSession . $userAgentFull . $this->getClientIp() . '_pidguin');
	}
	
	/**
	 *
	 */
	public function getClientInfo()
	{
		if ($this->_client) {
			return $this->_client;
		}
		
		$this->clientIdentity();
		return $this->_client;
	}
	
	/**
	 * Get Client Id
	 *
	 * @throw Exception
	 * @return string
	 */
	public function getCid()
	{
		if ($this->getUserId() <= 0) {
			throw new \Exception('User id is not set');
		}
		
		$user = $this->getUserModel();
		$userRow = $user->findUserById($this->getUserId());
		
		if (!$userRow) {
			throw new \Exception('User not found');
		}
		
		$hash = $this->getClientIdFromData() . md5($userRow->hash . $userRow->login . $userRow->id . '_user-Pidguin');
		
		return $hash;
	}
	
	/**
	 * Set cookie cid
	 *
	 * @param string $cid
	 */
	public function setCid($cid)
	{
		setcookie('cid', $cid, time() + 3024000, '/', '', false, true);
	}
	
	/**
	 * Get CID from cookie
	 *
	 * @return string|null
	 */
	public function getCookieCid()
	{
		$cid = (isset($_COOKIE['cid'])) ? $_COOKIE['cid'] : null;
		
		if ($cid !== null) {
			if (preg_match('/[a-z0-9]{96}/', $cid)) {
				return $cid;
			}
		}
		return null;
	}
	
	/**
	 * Get SID from cookie
	 *
	 * @return string|null
	 */
	public function getCookieSid()
	{
		$sid = (isset($_COOKIE['sid'])) ? $_COOKIE['sid'] : null;
		
		if ($sid !== null) {
			if (preg_match('/[a-z0-9]{26}/', $sid)) {
				return $sid;
			}
		}
		return null;
	}
	
	/**
	 * Check cookie cid
	 *
	 * @return boolean
	 */
	public function checkCid()
	{
		$cid = $this->getCookieCid();
		
		if ($cid !== null) {
			if ($cid === $this->getCid()) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Return user model
	 *
	 * @return object Model_User
	 */
	public function getUserModel()
	{
		if (!$this->_userModel) {
			$this->_userModel = Model_User::getInstance();
		}
		return $this->_userModel;
	}
	
	/**
	 * Return client model
	 *
	 * @return object Model_Client
	 */
	public function getClientModel()
	{
		if (!$this->_clientModel) {
			$this->_clientModel = Model_Client::getInstance();
		}
		return $this->_clientModel;
	}
	
	/**
	 * Set user id
	 *
	 * @param int $id
	 */
	public function setUserId($id)
	{
		$this->_userId = intval($id);
	}
	
	/**
	 * Get user id
	 *
	 * @return int
	 */
	public function getUserId()
	{
		return $this->_userId;
	}
	
	/**
	 * Start session
	 *
	 * @return void
	 */
	public function sessionStart()
	{
		Zend_Session::setOptions(array('name' => 'sid'));
		$saveHandler = new Zend_Session_SaveHandler_DbTable(array(
			'name'           => 'clients',
			'primary'        => 'sid',
			'modifiedColumn' => 'modified_at',
			'dataColumn'     => 'session_data',
			'lifetimeColumn' => 'lifetime'
		));
		
		Zend_Session::setSaveHandler($saveHandler);
		Zend_Session::start();
	}
	
	/**
	 * Get object userAgent
	 *
	 * @return object Zend_Http_UserAgent
	 */
	public function getUserAgent()
	{
		if ($this->_userAgent) {
			return $this->_userAgent;
		}
		$this->_userAgent = new Zend_Http_UserAgent();
		$this->_userAgent->setStorage(new Zend_Http_UserAgent_Storage_NonPersistent());
		return $this->_userAgent;
	}
	
	/**
	 * Get client ip
	 *
	 * @return string
	 */
	public function getClientIp()
	{
		return $this->getUserAgent()->getDevice()->getFeature('client_ip');
	}
	
	/**
	 * Get browser name
	 *
	 * @return string
	 */
	public function getClientBrowserName()
	{
		return $this->getUserAgent()->getDevice()->getFeature('browser_name');
	}
	
	/**
	 * Get device type
	 *
	 * @return string
	 */
	public function getDeviceType()
	{
		if ($this->_deviceType) {
			return $this->_deviceType;
		}
		
		$getDeviceType = function($device) {
			if ($device->getFeature('is_wireless_device')) {
				return 'wireless_device';
			} elseif ($device->getFeature('is_mobile')) {
				return 'mobile';
			} elseif ($device->getFeature('is_desktop')) {
				return 'destop';
			} elseif ($device->getFeature('is_tablet')) {
				return 'tablet';
			} elseif ($device->getFeature('is_bot')) {
				return 'bot';
			} elseif ($device->getFeature('is_email')) {
				return 'email';
			} elseif ($device->getFeature('is_text')) {
				return 'text';
			} else {
				return 'unknow';
			}
		};
		
		$this->_deviceType = $getDeviceType($this->getUserAgent()->getDevice());
		
		return $this->_deviceType;
	}
	
	/**
	 * Identify client
	 *
	 * @return void
	 */
	public function clientIdentity()
	{
		$modelClient = $this->getClientModel();
		$clientRow = $modelClient->fetchRow(
				$modelClient->select()->where(
						$modelClient->getAdapter()->quoteInto('sid = ?', Zend_Session::getId())
				)
		);
		
		$modelUser = $this->getUserModel();
		$uid = $modelUser->getGuestId();
		$auth = null;
		if ($clientRow) {
			if (!empty($clientRow->session_data)) {
				$auth = strtr($clientRow->session_data, array('auth|' => ''));
				$auth = unserialize($auth);
				if (isset($auth['uid'])) {
					$uid = $auth['uid'];
				}
			}
			$clientRow->ip = $this->getClientIp();
			$clientRow->browser = $this->getClientBrowserName();
			$clientRow->device_type = $this->getDeviceType();
			$clientRow->save();
		}
		$updates = null;
		switch ($this->getUserAgent()->getDevice()->getBrowser()) {
			case 'Chrome':
					if ($this->getUserAgent()->getDevice()->getBrowserVersion() + 0 < '21.0.1180.60' + 0) {
						$updates = true;
					}
				break;
			case 'Internet Explorer':
					if ($this->getUserAgent()->getDevice()->getBrowserVersion() + 0 < '9.0' + 0) {
						$updates = true;
					}
				break;
			case 'Firefox':
					if ($this->getUserAgent()->getDevice()->getBrowserVersion() + 0 < '3.5.6' + 0) {
						$updates = true;
					}
				break;
			case 'Opera':
					if ($this->getUserAgent()->getDevice()->getBrowserVersion() + 0 < '11.60' + 0) {
						$updates = true;
					}
				break;
		}
		if ($updates !== null) {
			$browser_name = $this->getUserAgent()->getDevice()->getBrowser();
			$browser_version = $this->getUserAgent()->getDevice()->getBrowserVersion();
			include 'Application/Modules/public/views/scripts/index/browser-update.php';
			die();
		}
		
		$userRow = $modelUser->fetchRow(
			$modelUser->select()->where(
				$modelUser->getAdapter()->quoteInto('id = ?', $uid)
			)
		);
		
		if (!$userRow) {
			throw new Exception('User not found');
		}
		
		if ($userRow->login != 'guest') {
			$hash = hash('sha256',
					$this->getClientBrowserName()
					. $this->getDeviceType()
					. $_SERVER['HTTP_USER_AGENT']
					. $this->getClientIp()
					. '_pidguin')
					. md5($userRow->id . $userRow->hash . '-user-pidguin');
			if ($auth === null || !isset($auth['hash']) || $hash != $auth['hash']) {
				$userRow = $modelUser->getGuestRow();
			}
		}
		
		$acl = new Zend_Acl();
		
		$groupRowset = $userRow->findDependentRowset('Model_UserGroup', 'User');
		// получаем группы пользователя
		foreach($groupRowset as $group) {
			$groups[] = $group->findParentRow('Model_Groups');
		}
		
		// устанавливаем роли в Zend_Acl
		foreach ($groups as $group) {
			$access = $group->findDependentRowset('Model_Access', 'Group');
			$acl->addRole($group->name);
			foreach($access as $_access){
				$resource = $_access->findParentRow('Model_Resource', 'Resource');
				$module = $resource->findParentRow('Model_Module');
				$action = $module->name . '::' . $resource->action;
				if (!$acl->has($action)) {
					$acl->addResource($action);
				}
				if ($_access->allow == 1) {
					$acl->allow($group->name, $action);
				} else {
					$acl->deny($group->name, $action);
				}
			}
		}
		
		$this->_acl = $acl;
		$this->_client = new stdClass();
		$this->_client->sid = Zend_Session::getId();
		$this->_client->user = $userRow;
		$this->_client->groups = $groups;
        
        $this->_session['auth'] = new Zend_Session_Namespace('auth');
        $this->_session['auth']->uid = $userRow->id;
	}
	
	public function isAccess(Zend_Controller_Request_Abstract $request)
	{
		$resources = $this->_acl->getResources();
		$action = strtolower($request->getModuleName()
				. '::' . $request->getControllerName()
				. '::' . $request->getActionName());
		$access = false;
		foreach ($resources as $resource) {
			$_resource = strtr($resource, array(':' => '\:', '*' => '(.*)', '.', '\.'));
			if (preg_match('/^'.$_resource.'$/i', $action)) {
				foreach ($this->_client->groups as $group) {
					if ($this->_acl->isAllowed($group->name, $resource)) {
						$access = true;
						break;
					} else {
						$access = false;
					}
				}
				break;
			}
		}
		return $access;
	}
	
	public function authorize($user, $cp = false, $quick_expire = false)
	{
		$acl = new Zend_Acl();
		$groupRowset = $user->findDependentRowset('Model_UserGroup', 'User');
		// получаем группы пользователя
		$groups = array();
		foreach($groupRowset as $group) {
			$groups[] = $group->findParentRow('Model_Groups');
		}
		
		// устанавливаем роли в Zend_Acl
		foreach ($groups as $group) {
			$access = $group->findDependentRowset('Model_Access', 'Group');
			$acl->addRole($group->name);
			foreach($access as $_access){
				$resource = $_access->findParentRow('Model_Resource', 'Resource');
				$module = $resource->findParentRow('Model_Module');
				$action = $module->name . '::' . $resource->action;
				if (!$acl->has($action)) {
					$acl->addResource($action);
				}
				if ($_access->allow == 1) {
					$acl->allow($group->name, $action);
				} else {
					$acl->deny($group->name, $action);
				}
			}
		}
        
        $resources = $acl->getResources();
        $action = ($cp) ? 'cp::*::*' : 'public::personal.page::*';
        $access = false;
        foreach ($resources as $resource) {
            $_resource = strtr($resource, array(':' => '\:', '*' => '(.*)'));
            if (preg_match('/^'.$_resource.'$/i', $action)) {
                foreach ($groups as $group) {
                    if ($acl->isAllowed($group->name, $resource)) {
                        $access = true;
                        break;
                    } else {
                        $access = false;
                    }
                }
                break;
            }
        }
		if ($access) {
			$hash = hash('sha256',
				$this->getClientBrowserName()
				. $this->getDeviceType()
				. $_SERVER['HTTP_USER_AGENT']
				. $this->getClientIp()
				. '_pidguin')
				. md5($user->id . $user->hash . '-user-pidguin');
			$this->_session['auth'] = new Zend_Session_Namespace('auth');
			$this->_session['auth']->uid = $user->id;
			$this->_session['auth']->hash = $hash;
            if ($quick_expire == false) {
                Zend_Session::rememberMe(36000000);
            }
			return true;
		} else {
			return false;
		}
	}
	
	public function logout()
	{
		Zend_Session::forgetMe();
		$_SESSION = null;
	}
}
